package com.aispeech.rcprvd.utils;


import android.app.Application;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.util.Log;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author rain  12.12 2018
 */

public class UsbPermissionRequestManager {

    private final static String TAG = "UsbRequestManager";
    private static final String ACTION_USB_PERMISSION = "com.aispeech.hid.USB_PERMISSION";

    private static Application mContext;

    private boolean isRequesting = false;
    private static Map<UsbDevice, UsbPmsListener> mReqDevsMap;

    private UsbPermissionRequestManager() {
        Log.d(TAG, "UsbPermissionRequestManager: ");
        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
        mContext.registerReceiver(mUsbPermissionReceiver, filter);
        mReqDevsMap = new LinkedHashMap<>();
    }

    private static class SingletonHolder {

        private static final UsbPermissionRequestManager INSTANCE = new UsbPermissionRequestManager();
    }

    public static UsbPermissionRequestManager getInstance(Application context) {
        mContext = context;
        return SingletonHolder.INSTANCE;
    }

    public void requestPermission(UsbDevice usbDevice, UsbPmsListener listener) {
        Log.d(TAG, "requestPermission with: usbDevice = " + usbDevice);
        if (null == usbDevice || null == listener) {
            Log.e(TAG, "requestPermission: Illegal Argument,usbDevice or listener is null");
            return;
        }
        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
        if (null == usbManager) {
            listener.onFail("can not get usb manager");
            return;
        }
        if (usbManager.hasPermission(usbDevice)) {
            Log.w(TAG, "requestPermission: already has permission ");
            listener.onSuccess();
            return;
        }
        synchronized (UsbPermissionRequestManager.this) {
            if (isRequesting) {
                mReqDevsMap.put(usbDevice, listener);
                Log.d(TAG, "requestPermission: isRequesting put to mReqDevsMap size = " + mReqDevsMap.size());
            } else {
                //request now
                isRequesting = true;
                mReqDevsMap.put(usbDevice, listener);
                reqUsbDevPermission(usbDevice);
            }
        }
    }

    private void reqUsbDevPermission(UsbDevice mDevice) {
        Log.d(TAG, "reqUsbDevPermission: vid = " + mDevice.getVendorId() + " pid = " + mDevice.getProductId());

        PendingIntent mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);

        if (usbManager != null) {
            usbManager.requestPermission(mDevice, mPermissionIntent);
        } else {
            Log.e(TAG, "reqUsbDevPermission: can not get usbmanager");
            isRequesting = false;
            mReqDevsMap.get(mDevice).onFail("can not get usbmanager");
            mReqDevsMap.remove(mDevice);
        }
    }

    private final BroadcastReceiver mUsbPermissionReceiver = new BroadcastReceiver() {

        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "mUsbPermissionReceiver " + action);
            synchronized (UsbPermissionRequestManager.this) {
                if (ACTION_USB_PERMISSION.equals(action)) {
                    UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    Log.d(TAG, "mUsbPermissionReceiver: device = " + device);

                    boolean permission = intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
                    Log.d(TAG, "onReceive: mReqDevsMap size = " + mReqDevsMap.size());
                    Log.d(TAG, "onReceive: mReqDevsMap = " + mReqDevsMap);
                    UsbPmsListener usbPermissionListener = null;
                    if (mReqDevsMap.containsKey(device)) {
                        usbPermissionListener = mReqDevsMap.get(device);
                        mReqDevsMap.remove(device);

                    } else {
                        Log.w(TAG, "the device maybe plug out or user input back key");
                        Log.w(TAG, "use device name to find listener");
                        for (UsbDevice usbDevice : mReqDevsMap.keySet()) {
                            if (usbDevice.getDeviceName().equals(device.getDeviceName())) {
                                usbPermissionListener = mReqDevsMap.get(usbDevice);
                                mReqDevsMap.remove(usbDevice);
                                break;
                            }
                        }
                    }

                    if (null != usbPermissionListener) {
                        if (permission) {
                            Log.d(TAG, "mUsbPermissionReceiver: permission success");
                            usbPermissionListener.onSuccess();
                        } else {
                            Log.d(TAG, "mUsbPermissionReceiver: permission fail");
                            usbPermissionListener.onFail("user didn't grant permissions");
                        }
                    } else {
                        Log.e(TAG, "onReceive: can not find target usedevice");
                    }

                    isRequesting = false;
                    if (!mReqDevsMap.isEmpty()) {
                        for (UsbDevice usbDevice : mReqDevsMap.keySet()) {
                            UsbPmsListener usbListener = mReqDevsMap.get(usbDevice);
                            requestPermission(usbDevice, usbListener);
                            return;//just get one
                        }
                    } else {
                        Log.w(TAG, "onReceive: mReqDevsMap is empty");
                    }
                }
            }
        }
    };

    public interface UsbPmsListener {

        void onSuccess();

        void onFail(String err);
    }
}
